<?php

// ------------------------------------------------------------------------
// |@Author       : Jarmin <edshop@qq.com>
// |@----------------------------------------------------------------------
// |@Date         : 2025-04-25 10:54:44
// |@----------------------------------------------------------------------
// |@LastEditTime : 2025-04-25 15:51:27
// |@----------------------------------------------------------------------
// |@LastEditors  : Jarmin <jarmin@ladmin.cn>
// |@----------------------------------------------------------------------
// |@Description  : 插件路由
// |@----------------------------------------------------------------------
// |@FilePath     : Route.php
// |@----------------------------------------------------------------------
// |@Copyright (c) 2025 http://www.ladmin.cn   All rights reserved.
// ------------------------------------------------------------------------

declare(strict_types=1);

namespace think\addons;

use think\helper\Str;
use think\exception\HttpException;
use RuntimeException;

class Route
{
    /**
     * 缓存键前缀
     */
    private const CACHE_PREFIX = 'addons_route_';

    /**
     * 插件路由请求
     *
     * 处理插件路由请求，包括：
     * 1. 获取路由参数
     * 2. 验证插件信息
     * 3. 加载控制器
     * 4. 执行操作方法
     *
     * @return mixed
     * @throws HttpException 路由处理失败时抛出异常
     */
    public static function execute()
    {
        try {
            $app = app();
            $request = $app->request;

            // 获取路由参数
            $params = self::getRouteParams($request);

            // 触发插件开始事件
            $app->event->trigger('addons_begin', $request);

            // 验证插件信息
            $info = self::validateAddon($params['addon']);

            // 设置请求参数
            self::setRequestParams($request, $params);

            // 触发模块初始化事件
            $app->event->trigger('addon_module_init', $request);

            // 加载控制器
            $instance = self::loadController($params['addon'], $params['controller']);

            // 设置视图路径
            self::setViewPath($app, $params['addon']);

            // 执行操作方法
            return self::executeAction($instance, $params['action']);
        } catch (HttpException $e) {
            throw $e;
        } catch (\Exception $e) {
            $app->log->error('Addons route execute failed: ' . $e->getMessage());
            throw new HttpException(500, $e->getMessage());
        }
    }

    /**
     * 获取路由参数
     *
     * @param \think\Request $request 请求对象
     * @return array 路由参数
     * @throws HttpException 参数无效时抛出异常
     */
    private static function getRouteParams($request): array
    {
        $addon = $request->route('addon');
        $controller = $request->route('controller', 'index');
        $action = $request->route('action', 'index') ?: 'index';

        if (empty($addon) || empty($controller) || empty($action)) {
            throw new HttpException(500, lang('addon can not be empty'));
        }

        return [
            'addon' => $addon,
            'controller' => $controller,
            'action' => $action
        ];
    }

    /**
     * 验证插件信息
     *
     * @param string $addon 插件名称
     * @return array 插件信息
     * @throws HttpException 插件无效时抛出异常
     */
    private static function validateAddon(string $addon): array
    {
        $info = get_addons_info($addon);
        if (!$info || !is_array($info)) {
            throw new HttpException(404, lang('addon %s not found', [$addon]));
        }
        if (isset($info['status']) && !$info['status']) {
            throw new HttpException(500, lang('addon %s is disabled', [$addon]));
        }
        return $info;
    }

    /**
     * 设置请求参数
     *
     * @param \think\Request $request 请求对象
     * @param array $params 路由参数
     */
    private static function setRequestParams($request, array $params): void
    {
        $request->addon = $params['addon'];
        $request->setController($params['controller'])
                ->setAction($params['action']);
    }

    /**
     * 加载控制器
     *
     * @param string $addon 插件名称
     * @param string $controller 控制器名称
     * @return object 控制器实例
     * @throws HttpException 控制器加载失败时抛出异常
     */
    private static function loadController(string $addon, string $controller): object
    {
        $class = get_addons_class($addon, 'controller', $controller);
        if (!$class) {
            throw new HttpException(404, lang('addon controller %s not found', [Str::studly($controller)]));
        }

        try {
            return new $class(app());
        } catch (\Exception $e) {
            throw new HttpException(404, lang('addon controller %s not found', [Str::studly($controller)]));
        }
    }

    /**
     * 设置视图路径
     *
     * @param \think\App $app 应用实例
     * @param string $addon 插件名称
     */
    private static function setViewPath($app, string $addon): void
    {
        $config = $app->config->get('view');
        $config['view_path'] = $app->addons->getAddonsPath() . $addon . DIRECTORY_SEPARATOR . 'view' . DIRECTORY_SEPARATOR;
        $app->config->set($config, 'view');
    }

    /**
     * 执行操作方法
     *
     * @param object $instance 控制器实例
     * @param string $action 操作方法
     * @return mixed
     * @throws HttpException 方法执行失败时抛出异常
     */
    private static function executeAction(object $instance, string $action)
    {
        $vars = [];
        if (is_callable([$instance, $action])) {
            $call = [$instance, $action];
        } elseif (is_callable([$instance, '_empty'])) {
            $call = [$instance, '_empty'];
            $vars = [$action];
        } elseif (is_callable([$instance, '__call'])) {
            $call = [$instance, '__call'];
            $vars = [$action];
        } else {
            throw new HttpException(404, lang('addon action %s not found', [get_class($instance).'->'.$action.'()']));
        }

        app()->event->trigger('addons_action_begin', $call);
        return call_user_func_array($call, $vars);
    }
}
